#include <fstream>
#include <sstream>
#include "MundoServicio.h"
#include "ProtocoloConstantes.h"
#include "ServicioConstantes.h"

using namespace std;
using namespace TP::Servicios;
using namespace TP::Comunicacion;
using namespace TP::Threading;

MundoServicio::MundoServicio(const string &pathMundos) {
    _pathMundos = pathMundos;
}

MundoServicio::~MundoServicio() {
}

void MundoServicio::iniciar() {
    _exploradorDirectorios.cargarDirectorios(_pathMundos);
}
    
void MundoServicio::finalizar() {
    
}

void MundoServicio::mensajeEntranteManejador (IMensajero* pMensajero, const string& pMensaje) {
    
    try
    {
        vector<string> comando;
        this->hidratarMensaje(pMensaje, comando);
        
        if (MUNDO == comando[0])
        {
            if (LISTAR_MUNDOS == comando [1])
                this->__listarMundos (pMensajero);
            
            if (LISTAR_NIVELES == comando[1])
                this->__listarNiveles(pMensajero, comando);
        }
    }
    catch (Excepcion& pEx)
    {
        cerr << pEx.what() << endl;
    }
}

void MundoServicio::__listarMundos(IMensajero* pMensajero) {
    
    std::stringstream respuesta;
    respuesta << "";
    
    string pathArchivo;

    TiXmlDocument xmlDoc;
    vector<string> lArchMundos;
    vector<string>::iterator it;
    TiXmlElement* mundoElement = 0;
    
    _mutex.lock();
    lArchMundos = _exploradorDirectorios.getDirectorios();

    for(it = lArchMundos.begin(); it != lArchMundos.end(); ++it) {

        pathArchivo = _pathMundos + (*it);  // Genero el path del archivo
        FILE *docfd = fopen(pathArchivo.c_str(), "r");  // Obtengo el fd
        if (docfd)
        {
            if(xmlDoc.LoadFile(docfd)) {  // Levanto el xml

                if (respuesta.str().length() > 0)
                    respuesta << SEPARADOR_CAMPO_LISTA;

                mundoElement = xmlDoc.FirstChildElement("Mundo");
                respuesta << mundoElement->Attribute("nombre");
            }
            fclose(docfd);
        }
    }
    _mutex.unlock();
    this->notificar(pMensajero, respuesta.str());
}

void MundoServicio::__listarNiveles(IMensajero* pMensajero, vector<string>& pComando) {
    
    if (pComando.size() != 3)
    {
        this->notificarError(pMensajero, "Formato de comando incorrecto.");
        return;
    }
    
    _mutex.lock();
    std::stringstream respuesta;
    respuesta << "";
    vector<string> lArchMundos = _exploradorDirectorios.getDirectorios();

    bool encontrado = false;

    for (vector<string>::iterator it = lArchMundos.begin(); it != lArchMundos.end() && !encontrado; ++it)
    {
        string pathArchivo = _pathMundos + (*it);
        FILE *docfd = fopen(pathArchivo.c_str(), "r");

        if (docfd)
        {
            TiXmlDocument xmlDoc;

            if(xmlDoc.LoadFile(docfd)) {
                TiXmlElement* mundoElement = xmlDoc.FirstChildElement("Mundo");
                string nombre = pComando [2];

                if(encontrado = (mundoElement->Attribute("nombre") == nombre)) {
                    TiXmlElement* elementAux = mundoElement->FirstChildElement(); /*Niveles*/

                    if (elementAux){
                        // El mundo posee niveles definidos.
                        elementAux = elementAux->FirstChildElement();

                        while (NULL != elementAux) {
                            if (respuesta.str().length() > 0)
                                respuesta << SEPARADOR_CAMPO_LISTA;
                            respuesta << elementAux->Attribute("id");
                            elementAux = elementAux->NextSiblingElement();
                        }
                    }
                }
            }
            fclose(docfd);
        }
    }
    _mutex.unlock();
    if (encontrado)
        this->notificar(pMensajero, respuesta.str());    
    else
        this->notificar(pMensajero, NULO);
    
}

Mundo* MundoServicio::getMundoPorNombre(const string& pNombreMundo){
    
    try
    {
        // El nombre del mundo se especifica en el nombre del archivo.
        string path = this->_pathMundos;
        path += pNombreMundo;
        path += ".xml";
        
        ifstream stream (path.c_str());
        
        if (stream.is_open())
        {
            // El mundo existe.  Lo hidrato y lo retorno.

            // Cargo el mundo en un string.
            std::stringstream strstream;
            string item = "";
            
            while (std::getline (stream, item, '\n'))
                strstream << item << endl;
            
            // Hidrato el mundo y lo retorno.
            return Mundo::crearDeXML (strstream.str());
        }
        return NULL;
    }
    catch (Excepcion& pEx)
    {
        cerr << pEx.what() << endl;
    }
}